package surreal.triviamaster.utilities;

import java.io.IOException;
import java.util.ArrayList;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import surreal.triviamaster.beans.Answer;
import surreal.triviamaster.beans.Category;
import surreal.triviamaster.beans.LikelyAnswer;
import surreal.triviamaster.beans.Question;
import surreal.triviamaster.database.LocalCache;

import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class TriviaMasterService extends IntentService {

	private LocalCache db;
	
	public TriviaMasterService() {
		super("TriviaMasterService");
		System.out.println("Constructor");
		
	}
	@Override
	  public void onCreate() {
	    super.onCreate();
	   System.out.println("On Create");
	    db = ((TriviaMasterApplication) getApplication()).getLocalCache();
	}

	@Override
	protected void onHandleIntent(Intent intent){
		
	      if (Utilities.isNetworkAvailable(this)) {

		      if (intent.getAction().equals(TriviaMasterApplication.ACTION_GET_QUESTIONS)) {
		    	  getQuizQuestions(intent);
		      } else if (intent.getAction().equals(TriviaMasterApplication.ACTION_REFRESH_CATEGORIES)) {
				   	refreshCategories(intent);
		      } else if (intent.getAction().equals(TriviaMasterApplication.ACTION_INSERT_QUESTION)) {
			      	insertQuestion(intent);
			  } else if (intent.getAction().equals(TriviaMasterApplication.ACTION_EMPTY_QUESTIONS)) {
			      	emptyQuestions(intent);
			  } else if (intent.getAction().equals(TriviaMasterApplication.ACTION_AUTHENTICATE)) {
			      	authenticate(intent);
			  } else if (intent.getAction().equals(TriviaMasterApplication.ACTION_FLUSH)) {
			      	flush(intent);
			  }
	      } else {
	    	  Log.d("Service", TriviaMasterApplication.NETWORK_ERROR);
	      }
	}
	
	/**
	 * Flushes all data from the local cache to the server
	 * @param intent The intent that called with method
	 */
	private void flush(Intent intent) {
		
		Question[] qList = db.getQuizQuestions();
		//Flush quiz results
		flushQuizResults(qList);        
        //Flush quiz flags
		flushQuizFlags(qList);			
        //delete old questions
        db.deleteQuizQuestions();
	}
	
	/**
	 * Takes the given list of questions and submits all the guesses(correct or incorrect)
	 * the remote server
	 * @param qList A list of questions
	 */
	private void flushQuizResults(Question[] qList) {
		String toServer="";
		
		//putting together the guess information
		for(int i=0;i<qList.length;i++) {
			toServer+=qList[i].getId() + ";" + qList[i].getCorrectlyAnswered() +";"+ qList[i].getGuess() 
					+";"+ qList[i].getUsedHint()+";"+ qList[i].getUsedMC()+";;"; 
		}
		toServer=toServer.substring(0, toServer.length()-2);
		//putting together the MC data if MC was used
		String tmp ="";
		for(int i=0;i<qList.length;i++) {
			if(qList[i].getUsedMC()==1) {
				tmp+=qList[i].getFalseAnswersSplitId() + ";;"; 
			}
		}
		if(tmp.length()>0) {
			tmp=tmp.substring(0, tmp.length()-2);
		}
		//adding in the user id 
		toServer=db.getUserId()+";;;"+toServer + ";;;" + tmp;
		Log.d("Service flush", "Flush Results: " +toServer);
		
		ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
		postParameters.add(new BasicNameValuePair("action", TriviaMasterApplication.ACTION_RECORD_QUIZ_RESULTS));
        postParameters.add(new BasicNameValuePair("hash", db.getUserHash()));
        postParameters.add(new BasicNameValuePair("data", toServer));
        Bundle content = postWithResponse(TriviaMasterApplication.URL_PHP_ADDRESS+"handler.php", postParameters);
        Log.d("Service flush", "Flush Results: " +content.getString("content"));
		
	}
	/**
	 * Takes the given list of questions and submits all the flags associated with those questions to 
	 * the remote server
	 * @param qList A list of questions
	 */
	private void flushQuizFlags(Question[] qList) {
		String toServer="";
        for(int i=0;i<qList.length;i++) {
			if(qList[i].getFlag()>0) {
				Log.d("flush quiz flags", ""+qList[i].getId());
				toServer+=db.getFlag(qList[i].getId()).toUploadString()+";;";
			}
		}

		//if there is some flags to upload
		if(!toServer.equals("")) {
			
			toServer=toServer.substring(0, toServer.length()-2);
			//adding the users id number
			toServer=db.getUserId()+";;;"+toServer;
			Log.d("Service flush quiz flags", toServer);
			
			ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
			postParameters.add(new BasicNameValuePair("action", TriviaMasterApplication.ACTION_RECORD_FLAGS));
	        postParameters.add(new BasicNameValuePair("hash", db.getUserHash()));
	        postParameters.add(new BasicNameValuePair("fList", toServer));
	        Bundle content = postWithResponse(TriviaMasterApplication.URL_PHP_ADDRESS+"recordFlags.php", postParameters);
	        Log.d("flush quiz flags", content.getString("content"));
		}
	}

	/*
	 * Checks to see if this user has a hash.  If it does have a hash, check with the server to make sure it is valid
	 */
	
	private void authenticate(Intent intent) {
		
		ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
		postParameters.add(new BasicNameValuePair("action", TriviaMasterApplication.ACTION_AUTHENTICATE));
        postParameters.add(new BasicNameValuePair("hash", db.getUserHash()));
        Bundle bundle = postWithResponse(TriviaMasterApplication.URL_PHP_ADDRESS+"handler.php", postParameters);
        Log.d("Service", "Authenticating..."+db.getUserHash());
        if (bundle != null) {
        	String[] data = bundle.getString("content").split(";");
   
            //if true it is the users first time using this app
        	if(db.getUserHash().equals("null")) {
            	db.insertUser(data[0],data[1]);
            	Log.d("Service", "New User");
            } else{
            	Log.d("Service", "Login Recorded");	
            }
        	Log.d("Service", "Content: " + bundle.getString("content"));	
        } else {
        	Log.d("Service", "Authentification Failed");
        }
	}
	/*
	 * Emptys the questions from the server side database
	 */
	
	private void emptyQuestions(Intent intent) {
		ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
		postParameters.add(new BasicNameValuePair("action", TriviaMasterApplication.ACTION_EMPTY_QUESTIONS));
        postParameters.add(new BasicNameValuePair("hash", db.getUserHash()));
        postParameters.add(new BasicNameValuePair("code", intent.getStringExtra("code")));
        postNoResponse(TriviaMasterApplication.URL_PHP_ADDRESS+"handler.php", postParameters);
	}
	/**
	 * Inserts a question into the database?  Should we load this to the local cache first?
	 */
	private void insertQuestion(Intent intent) {
		
		ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
		postParameters.add(new BasicNameValuePair("action", TriviaMasterApplication.ACTION_INSERT_QUESTION));
        postParameters.add(new BasicNameValuePair("hash", db.getUserHash()));
        postParameters.add(new BasicNameValuePair("question", intent.getStringExtra("question")));
        postParameters.add(new BasicNameValuePair("acceptableAnswers", intent.getStringExtra("acceptableAnswers")));
        postParameters.add(new BasicNameValuePair("userId", ""+intent.getIntExtra("userId", 0)));
        postParameters.add(new BasicNameValuePair("categories", intent.getStringExtra("categories")));
        
        String hint = intent.getStringExtra("hint");
        if(hint.equals("")) {
        	hint = "null";
        }
        postParameters.add(new BasicNameValuePair("hint", hint));
        postParameters.add(new BasicNameValuePair("fAs", intent.getStringExtra("fList")));
        
        Log.d("sevice", "hint: " + intent.getStringExtra("hint") + " fAs: " + intent.getStringExtra("fList")+ " len: " + intent.getStringExtra("fList").length());
        
        	Bundle bundle = postWithResponse(TriviaMasterApplication.URL_PHP_ADDRESS+"handler.php", postParameters);
        	System.out.println(bundle.getString("content"));
	}
	
	/*
	 * Goes to the server, gets all categories and loads them into the local database
	 */
	private void refreshCategories(Intent intent) {
		
		Category[] cats = null;
		
		ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
		postParameters.add(new BasicNameValuePair("action", TriviaMasterApplication.ACTION_REFRESH_CATEGORIES));
		postParameters.add(new BasicNameValuePair("hash", ""+db.getUserHash()));
        Bundle bundle = postWithResponse(TriviaMasterApplication.URL_PHP_ADDRESS+"handler.php", postParameters);
        
        Log.d("Service", bundle.getString("content"));
        
        if (bundle != null) { 
            cats = Utilities.jsonToArrayCategories(bundle.getString("content"));
            db.refreshCategories(cats);
          }
	}
	
	private Bundle postWithResponse(String url,
			ArrayList<NameValuePair> postParameters) {
		String content = null;
	    Bundle bundle = null;

	    HttpClient client = new DefaultHttpClient();
	    HttpPost request = new HttpPost(url);

	    try {
	      UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters);
	      request.setEntity(formEntity);
	      ResponseHandler<String> handler = new BasicResponseHandler();
	      content = client.execute(request, handler);
	      bundle = new Bundle();
	      bundle.putString("content", content);
	    } catch (ClientProtocolException e) {
	      content = "client protocol error";
	    } catch (IOException e) {
	      content = "I/O error";
	    }
	    client.getConnectionManager().shutdown();

	    return bundle;
		
	}
	/**
	 * Returns the questions for the quiz
	 * @param intent The intent that called this request
	 */
	
	private void getQuizQuestions(Intent intent) {
		Question[] questions = null;
		Answer[] aAs = null;
		LikelyAnswer[] fAs = null;
		
		ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
		postParameters.add(new BasicNameValuePair("action", TriviaMasterApplication.ACTION_GET_QUESTIONS));
		postParameters.add(new BasicNameValuePair("hash", ""+db.getUserHash()));
        postParameters.add(new BasicNameValuePair("catId", ""+db.getCurrentQuizCategory()));
        Bundle bundle = postWithResponse(TriviaMasterApplication.URL_PHP_ADDRESS+"handler.php", postParameters);
        
        String[] content = bundle.getString("content").split(";;;;;");
        Log.d("get Questions", content[0]);
        Log.d("get Questions", content[1]);
        Log.d("get Questions", content[2]);
        if (bundle != null) {
        	questions = Utilities.jsonToArrayQuestions(content[0]);
        	aAs = Utilities.jsonToArrayAnswers(content[1]);
        	fAs = Utilities.jsonToArrayLikelyAnswers(content[2]);
            db.refreshQuestions(questions, aAs, fAs);
          }
		
	}
	/*
	 * Bundle returns nothing atm
	 */
	private Bundle postNoResponse(String url,
            ArrayList<NameValuePair> postParameters) {
		String content = "";
		Bundle bundle = null;
		
		HttpClient client = new DefaultHttpClient();
		HttpPost request = new HttpPost(url);
		
		try {
			UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters);
			
			request.setEntity(formEntity);
			System.out.println(request.toString());
			//ResponseHandler<String> handler = new BasicResponseHandler();
			client.execute(request);
			bundle = new Bundle();
			//bundle.putString("content", content);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			content = "client protocol error";
		} catch (IOException e) {
			e.printStackTrace();
			
			content = "I/O error";
		}
		System.out.println(content);
		client.getConnectionManager().shutdown();
		
		return bundle;
	}
}
	
